from datetime import date, datetime

import xlsxwriter
from flask import send_file, abort, jsonify, request

from aab import app
from aab.model import OutsideReturn, User, db, Group, Roles
from aab.utils import format_health, format_persons, fill_worksheet, success, approval_to_dict, login_required, \
    update_persons, do_approval, jsonify_error, DATE_FORMAT, SheetData


@app.route('/xlsx/outside', methods=['GET'])
@app.route('/xlsx/outside/<day>', methods=['GET'])
@login_required(roles=[Roles.ADMIN])
def generate_outside_xlsx(day=None):
    if day is None:
        day = date.today()
    else:
        day = datetime.strptime(day, DATE_FORMAT).date()
    return _generate_outside_xlsx(day)


def _generate_outside_xlsx(day):
    path = '/tmp/outside-{}__{}.xlsx'.format(day.strftime('%Y-%m-%d'),
                                             datetime.now().strftime('%Y-%m-%d-%H-%M-%S'))
    worksheet = SheetData(path)

    fields = [
        ('本人健康状况', format_health),
        ('当前所在省份城市与地区', 'current_address'),
        ('是否确定返回日期', lambda d: '是' if d.return_date_fixed else '否'),
        ('计划返程日期', 'plan_return_date'),
        ('计划车次/航班号/自驾车牌号', 'plan_traffic'),
        # ('其它需要说明的问题', 'comment'),
        ('计划隔离地点', 'plan_isolation_address'),
        ('计划同行人员', format_persons)
    ]

    worksheet.write(0, 0, '人员编号'),
    for j, field in enumerate(fields):
        worksheet.write(0, j + 1, field[0])

    for i, user in enumerate(User.query.order_by(User.number)):
        worksheet.write(i + 1, 0, user.number)

        outside_return = OutsideReturn.query.filter_by(user=user).filter(db.func.date(OutsideReturn.fill_time) <= day)\
            .order_by(OutsideReturn.fill_time.desc()).first()
        if not outside_return:
            continue

        fill_worksheet(worksheet, outside_return, i, fields)

    return worksheet.send_file()


@app.route('/user/<user_number>/outside-return', methods=['GET'])
@login_required
def query_outside_return(user_number):
    user = User.query.filter_by(number=user_number).scalar()
    if user is None:
        return jsonify_error(404, '用户不存在')

    outside_return = OutsideReturn.query.filter_by(user=user)\
        .order_by(OutsideReturn.fill_time.desc()).first()
    if outside_return is None:
        return jsonify_error(404, '未找到')

    return jsonify(_outside_return_to_dict(outside_return))


@app.route('/user/<user_number>/outside-return', methods=['DELETE'])
@login_required
def delete_outside_return(user_number):
    user = User.query.filter_by(number=user_number).scalar()
    if user is None:
        return jsonify_error(404, message='用户不存在')

    for outside_return in OutsideReturn.query.filter_by(user=user):
        for co_person in outside_return.co_persons:
            db.session.delete(co_person)
        db.session.delete(outside_return)

    db.session.commit()
    return success()


def _outside_return_to_dict(outside_return):
    result = outside_return.to_dict()
    result['persons'] = [p.to_dict() for p in outside_return.co_persons]
    result['approval'] = approval_to_dict(outside_return.approval)
    return result


@app.route('/group/<group_name>/outside-return', methods=['GET'])
@login_required(roles=[Roles.ADMIN, Roles.GROUP_MANAGER])
def query_group_outside_return(group_name):
    group = Group.query.filter_by(name=group_name).scalar()
    if group is None:
        return jsonify_error(404, '组不存在')

    outside_return_list = OutsideReturn.query.join(User).filter(User.group == group)\
        .order_by(OutsideReturn.fill_time.desc())
    return jsonify(_outside_return_list_to_dict(outside_return_list))


def _outside_return_list_to_dict(outside_return_list):
    result = []
    for outside_return in outside_return_list:
        d = _outside_return_to_dict(outside_return)
        d['user_number'] = outside_return.user.number
        result.append(d)
    return result


@app.route('/outside-returns', methods=['GET'])
@login_required(roles=[Roles.ADMIN])
def query_all_outside_return():
    outside_return_list = OutsideReturn.query.order_by(OutsideReturn.fill_time.desc()).all()
    return jsonify(_outside_return_list_to_dict(outside_return_list))


@app.route('/outside-return/<outside_return_id>/approval', methods=['PUT'])
@login_required(roles=[Roles.ADMIN, Roles.GROUP_MANAGER])
def approve_outside_return(outside_return_id):
    data = request.get_json()
    if data is None:
        return jsonify_error(400, message='Require JSON data')

    outside_return = OutsideReturn.query.filter_by(id=outside_return_id).scalar()
    if outside_return is None:
        return jsonify_error(404, message='返京申请未找到')

    return do_approval(outside_return, data.get('is_reject', False), data.get('to_admin', True))


@app.route('/user/<user_number>/outside-return', methods=['PUT'])
@login_required
def update_outside_return(user_number):
    user = User.query.filter_by(number=user_number).scalar()
    if user is None:
        return jsonify_error(404, message='用户不存在')

    data = request.get_json()
    if data is None:
        return jsonify_error(400, message='Require JSON data')

    outside_return = OutsideReturn.query.filter_by(user=user).order_by(OutsideReturn.fill_time.desc()).first()
    if outside_return is None:
        outside_return = OutsideReturn(user=user, fill_time=datetime.now()).update_from_dict(data)
        db.session.add(outside_return)
    else:
        outside_return.update_from_dict(data)
        outside_return.fill_time = datetime.now()

    update_persons(data, outside_return=outside_return)

    db.session.commit()
    return success()
